package com.dbsop.mapper;

import com.dbsop.EsClient;
import com.dbsop.common.util.EsFieldUtils;
import com.dbsop.common.util.EsPoJoUtils;
import com.dbsop.domain.info.EsFiledInfo;
import com.dbsop.operation.field.FieldOperation;
import com.dbsop.operation.index.IndexOperation;
import com.dbsop.operation.index.IndexParams;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 索引 映射的基础信息
 */
public class IndexMappingInfo<T,ID extends Serializable> {

    private Class<T> entity;

    /**
     * key es字段  Field 为实际字段
     */
    private List<EsFiledInfo> esFiledInfos;

    private Class idClass;

    private String indexName;

    private Integer maxResult;

    private Set<String> indices = new HashSet<>();

    private Integer shared;

    private Integer replicas;

    private String alias;

    private String idName;

    private ESBaseMapper esBaseMapper;

    /**
     * 校验成功的索引
     */
    private List<String> succeedIndex = new ArrayList<String>();
    /**
     * 是否自动创建字段
     */
    private boolean isAutoCreate = true;

    /**
     * 是否包含
     */
    private boolean isExt = false;

    /**
     * 是否
     */
    private boolean defaultAliasOpt = false;

    public IndexMappingInfo(Class<T> t,Class<ID> id) {
        if (entity == null || idClass== null) throw new RuntimeException(1+ ";请定义 实体类与ID 泛型");
        this.entity=t;
        this.idClass = id;
        initInfo();
    }

    public IndexMappingInfo(ESBaseMapper esBaseMapper) {
        this.esBaseMapper = esBaseMapper;
        Class repository = esBaseMapper.getClass();
        ParameterizedTypeImpl parameterizedType = (ParameterizedTypeImpl) (repository.getGenericSuperclass());
        Type[] typeArguments = parameterizedType.getActualTypeArguments();
        this.entity = (Class) typeArguments[0];
        this.idClass = (Class) typeArguments[0];
        if (entity == null || idClass== null) throw new RuntimeException(repository.getTypeName() + ";请定义 实体类与ID 泛型");
        initInfo();
        addIndices(esBaseMapper.indicesRules());
    }

    /**
     * 获取当前实体索引
     * @param indices
     * @param t
     * @return
     */
    public String getIndex(String indices, T t){
        if (indices != null ){
            return indices;
        }
        if (t !=null){
            String index = esBaseMapper.getIndex(t);
            if (!index.equals("-101")){
                return index;
            }
        }
        return  getIndexName();
    }

    /**
     * 确定索引记录
     * @param indices
     * @param t
     * @return
     */
    public String getValidIndex(String indices, T t){
        String index = getIndex(indices,t);
        checkIndex(index);
        return index;
    }

    /**
     * 分拣数据
     * @param ts
     * @return
     */
    public   Map<String,List<Map<String,Object>>> sortingData(List<T> ts, boolean isNull){
        Map<String,List<Map<String,Object>>> indexDataMap = new HashMap<String, List<Map<String,Object>>>();
        if (ts == null || ts.size() == 0){
            return indexDataMap;
        }
        for (T t : ts) {
            String index = getValidIndex(null, t);
            List<Map<String,Object>> tsSub = indexDataMap.get(index);
            if (tsSub == null){
                tsSub = new ArrayList<Map<String,Object>>();
                indexDataMap.put(index, tsSub);
            }
            if (!isNull){
                tsSub.add(EsPoJoUtils.getFieldValueMap(t,getFieldMap()));
            }else {
                tsSub.add(EsPoJoUtils.getFieldNotNullValueMap(t,getFieldMap()));
            }
        }
        return indexDataMap;
    }

    /**
     * 校验索引
     * @param indices
     */
    private void checkIndex(String... indices) {
        IndexOperation indexOperation = EsClient.getEsClient().getClientOpt().getIndexOperation();
        FieldOperation fieldOperation = EsClient.getEsClient().getClientOpt().getFieldOperation();
        List<String> succeedIndex = getSucceedIndex();
        for (String index : indices) {
            if (succeedIndex.contains(index)) {
                continue;
            }
            indexOperation.checkCreateIndex(new IndexParams(index,getAlias(),getShared(),getReplicas(),getMaxResult()));
            Boolean isSame = fieldOperation.checkIndexFields(index, esFiledInfos);
            if (!isSame)fieldOperation.createIndexFiled(index,esFiledInfos);
            addSucceedIndex(index);
        }
    }



    public List<String> getSucceedIndex() {
        return succeedIndex;
    }

    private void addIndices(String [] indiceArr){
        if (indiceArr == null || indiceArr.length ==0){
            return;
        }
        for (String index : indiceArr) {
            this.indices.add(index);
        }
    }

    public Set<String> getIndices() {
        return indices;
    }

    private void initInfo(){

        indexName = EsFieldUtils.getDocumentProperty(this.entity,"index_name");
        shared = EsFieldUtils.getDocumentProperty(this.entity,"share");
        replicas = EsFieldUtils.getDocumentProperty(this.entity,"replicas");
        alias = EsFieldUtils.getDocumentProperty(this.entity,"alias");
        addIndices(EsFieldUtils.indices(this.entity));
        isAutoCreate = EsFieldUtils.getDocumentProperty(this.entity,"isAutoCreate") ;
        isExt = EsFieldUtils.getDocumentProperty(this.entity,"isExt");
        defaultAliasOpt = EsFieldUtils.getDocumentProperty(this.entity,"default_alias_opt");
        this.maxResult = EsFieldUtils.getDocumentProperty(this.entity,"max_result");
        if (indexName == null)throw new RuntimeException(entity.getTypeName()+"; 请设置索引  ");
        idName = EsFieldUtils.getIdName(this.entity);
        esFiledInfos = EsFieldUtils.pareFieldInfo(entity,null);
    }

    public synchronized void addSucceedIndex(String index){
        if (!succeedIndex.contains(index)){
            succeedIndex.add(index);
        }
    }

    /**
     * 获取查询索引
     * @return
     */
    public String queryIndex(){
        if (defaultAliasOpt){
            return alias;
        }
        return indexName;
    }

    public String getAlias() {
        return alias;
    }

    public void setAlias(String alias) {
        this.alias = alias;
    }

    public boolean isExt() {
        return isExt;
    }

    public boolean isAutoCreate() {
        return isAutoCreate;
    }

    public void setAutoCreate(boolean autoCreate) {
        isAutoCreate = autoCreate;
    }

    public List<EsFiledInfo> getEsFiledInfos() {
        return esFiledInfos;
    }

    public Class getEntity() {
        return entity;
    }

    public void setEntity(Class entity) {
        this.entity = entity;
    }

    public Class getIdClass() {
        return idClass;
    }

    public void setIdClass(Class idClass) {
        this.idClass = idClass;
    }

    public String getIndexName() {
        return indexName;
    }




    public void setIndexName(String indexName) {
        this.indexName = indexName;
    }

    public String getIdName() {
        return idName;
    }

    public void setIdName(String idName) {
        this.idName = idName;
    }

    public Integer getShared() {
        return shared;
    }

    public void setShared(Integer shared) {
        this.shared = shared;
    }

    public Integer getReplicas() {
        return replicas;
    }

    public void setReplicas(Integer replicas) {
        this.replicas = replicas;
    }

    public Integer getMaxResult() {
        return maxResult;
    }

    public void setMaxResult(Integer maxResult) {
        this.maxResult = maxResult;
    }

    public Map<String,EsFiledInfo> getFieldMap() {
        Map<String,EsFiledInfo>  filedInfoMap = new LinkedHashMap<String, EsFiledInfo>();
        for (EsFiledInfo esFiledInfo : esFiledInfos) {
            filedInfoMap.put(esFiledInfo.getEsFieldName(),esFiledInfo);
        }
        return filedInfoMap;
    }
}
